"""API key validation functionality."""

import asyncio
import time
from typing import Dict, List, Optional, Tuple
from datetime import datetime, timedelta
import aiohttp
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
import motor.motor_asyncio
from bson import ObjectId

from ..models.api_key_model import APIKey, KeyProvider, KeyMetadata
from ..security.encryption import KeyEncryptor
from ..api.key_management import get_db, get_current_user


router = APIRouter(prefix="/api/keys", tags=["Key Validation"])

# Cache for validation results (in production, use Redis)
validation_cache: Dict[str, Tuple[Dict, datetime]] = {}
CACHE_TTL = timedelta(minutes=15)


class ValidationResult(BaseModel):
    """Validation result model."""
    is_valid: bool
    status: str
    response_time_ms: float
    supported_models: List[str]
    error: Optional[str] = None
    cached: bool = False


class KeyValidator:
    """API key validator for different providers."""
    
    def __init__(self):
        """Initialize validator."""
        self.validators = {
            KeyProvider.OPENAI: self._validate_openai,
            KeyProvider.ANTHROPIC: self._validate_anthropic,
            KeyProvider.BAIDU: self._validate_baidu,
            KeyProvider.XUNFEI: self._validate_xunfei,
            KeyProvider.MOONSHOT: self._validate_moonshot,
            KeyProvider.ALIBABA: self._validate_alibaba,
            KeyProvider.DEEPSEEK: self._validate_deepseek,
            KeyProvider.BYTEDANCE: self._validate_bytedance,
            KeyProvider.TENCENT: self._validate_tencent,
            KeyProvider.ZHIPU: self._validate_zhipu
        }
    
    async def validate(self, provider: KeyProvider, api_key: str) -> ValidationResult:
        """Validate API key for a specific provider.
        
        Args:
            provider: API key provider
            api_key: Decrypted API key
            
        Returns:
            Validation result
        """
        # Check cache first
        cache_key = f"{provider.value}:{hash(api_key)}"
        if cache_key in validation_cache:
            cached_result, cached_time = validation_cache[cache_key]
            if datetime.utcnow() - cached_time < CACHE_TTL:
                cached_result["cached"] = True
                return ValidationResult(**cached_result)
        
        # Get validator function
        validator_func = self.validators.get(provider)
        if not validator_func:
            return ValidationResult(
                is_valid=False,
                status="unsupported",
                response_time_ms=0,
                supported_models=[],
                error=f"Provider {provider.value} is not supported"
            )
        
        # Run validation
        start_time = time.time()
        try:
            result = await validator_func(api_key)
            response_time = (time.time() - start_time) * 1000
            
            validation_result = ValidationResult(
                is_valid=result["is_valid"],
                status=result.get("status", "validated"),
                response_time_ms=response_time,
                supported_models=result.get("models", []),
                error=result.get("error")
            )
            
            # Cache successful validation
            if result["is_valid"]:
                validation_cache[cache_key] = (validation_result.dict(), datetime.utcnow())
            
            return validation_result
            
        except Exception as e:
            response_time = (time.time() - start_time) * 1000
            return ValidationResult(
                is_valid=False,
                status="error",
                response_time_ms=response_time,
                supported_models=[],
                error=str(e)
            )
    
    async def _validate_openai(self, api_key: str) -> Dict:
        """Validate OpenAI API key."""
        url = "https://api.openai.com/v1/models"
        headers = {"Authorization": f"Bearer {api_key}"}
        
        async with aiohttp.ClientSession() as session:
            try:
                async with session.get(url, headers=headers, timeout=10) as response:
                    if response.status == 200:
                        data = await response.json()
                        models = [m["id"] for m in data.get("data", [])]
                        gpt_models = [m for m in models if "gpt" in m.lower()]
                        return {
                            "is_valid": True,
                            "status": "active",
                            "models": gpt_models[:5]  # Return top 5 models
                        }
                    elif response.status == 401:
                        return {
                            "is_valid": False,
                            "status": "invalid",
                            "error": "Invalid API key"
                        }
                    else:
                        return {
                            "is_valid": False,
                            "status": "error",
                            "error": f"API returned status {response.status}"
                        }
            except asyncio.TimeoutError:
                return {
                    "is_valid": False,
                    "status": "timeout",
                    "error": "Request timed out"
                }
            except Exception as e:
                return {
                    "is_valid": False,
                    "status": "error",
                    "error": str(e)
                }
    
    async def _validate_anthropic(self, api_key: str) -> Dict:
        """Validate Anthropic API key."""
        url = "https://api.anthropic.com/v1/messages"
        headers = {
            "x-api-key": api_key,
            "anthropic-version": "2023-06-01",
            "content-type": "application/json"
        }
        
        # Minimal test message
        data = {
            "model": "claude-3-haiku-20240307",
            "messages": [{"role": "user", "content": "Hi"}],
            "max_tokens": 1
        }
        
        async with aiohttp.ClientSession() as session:
            try:
                async with session.post(url, headers=headers, json=data, timeout=10) as response:
                    if response.status == 200:
                        return {
                            "is_valid": True,
                            "status": "active",
                            "models": ["claude-3-opus", "claude-3-sonnet", "claude-3-haiku"]
                        }
                    elif response.status == 401:
                        return {
                            "is_valid": False,
                            "status": "invalid",
                            "error": "Invalid API key"
                        }
                    else:
                        return {
                            "is_valid": False,
                            "status": "error",
                            "error": f"API returned status {response.status}"
                        }
            except Exception as e:
                return {
                    "is_valid": False,
                    "status": "error",
                    "error": str(e)
                }
    
    async def _validate_baidu(self, api_key: str) -> Dict:
        """Validate Baidu Wenxin API key."""
        # Baidu uses access token, not API key directly
        # This would need OAuth flow in production
        return {
            "is_valid": True,
            "status": "assumed_valid",
            "models": ["ernie-bot-4", "ernie-bot", "ernie-bot-turbo"],
            "error": "Baidu validation requires OAuth flow"
        }
    
    async def _validate_xunfei(self, api_key: str) -> Dict:
        """Validate Xunfei Spark API key."""
        # Xunfei uses complex auth with app_id, api_key, and api_secret
        return {
            "is_valid": True,
            "status": "assumed_valid",
            "models": ["spark-3.5", "spark-3.0", "spark-2.0"],
            "error": "Xunfei validation requires multiple credentials"
        }
    
    async def _validate_moonshot(self, api_key: str) -> Dict:
        """Validate Moonshot (Kimi) API key."""
        url = "https://api.moonshot.cn/v1/models"
        headers = {"Authorization": f"Bearer {api_key}"}
        
        async with aiohttp.ClientSession() as session:
            try:
                async with session.get(url, headers=headers, timeout=10) as response:
                    if response.status == 200:
                        data = await response.json()
                        models = [m["id"] for m in data.get("data", [])]
                        return {
                            "is_valid": True,
                            "status": "active",
                            "models": models
                        }
                    else:
                        return {
                            "is_valid": False,
                            "status": "invalid",
                            "error": "Invalid API key"
                        }
            except Exception as e:
                return {
                    "is_valid": False,
                    "status": "error",
                    "error": str(e)
                }
    
    async def _validate_alibaba(self, api_key: str) -> Dict:
        """Validate Alibaba Qwen API key."""
        # Would use DashScope API for validation
        return {
            "is_valid": True,
            "status": "assumed_valid",
            "models": ["qwen-max", "qwen-plus", "qwen-turbo"],
            "error": "Alibaba validation not fully implemented"
        }
    
    async def _validate_deepseek(self, api_key: str) -> Dict:
        """Validate DeepSeek API key."""
        url = "https://api.deepseek.com/v1/models"
        headers = {"Authorization": f"Bearer {api_key}"}
        
        async with aiohttp.ClientSession() as session:
            try:
                async with session.get(url, headers=headers, timeout=10) as response:
                    if response.status == 200:
                        return {
                            "is_valid": True,
                            "status": "active",
                            "models": ["deepseek-coder", "deepseek-chat"]
                        }
                    else:
                        return {
                            "is_valid": False,
                            "status": "invalid",
                            "error": "Invalid API key"
                        }
            except Exception as e:
                return {
                    "is_valid": False,
                    "status": "error",
                    "error": str(e)
                }
    
    async def _validate_bytedance(self, api_key: str) -> Dict:
        """Validate ByteDance Doubao API key."""
        # ByteDance uses Volcano Engine API
        return {
            "is_valid": True,
            "status": "assumed_valid",
            "models": ["skylark-chat", "skylark-lite", "skylark-pro"],
            "error": "ByteDance validation not fully implemented"
        }
    
    async def _validate_tencent(self, api_key: str) -> Dict:
        """Validate Tencent Hunyuan API key."""
        # Tencent uses complex signature auth
        return {
            "is_valid": True,
            "status": "assumed_valid",
            "models": ["hunyuan-standard", "hunyuan-lite", "hunyuan-pro"],
            "error": "Tencent validation requires signature auth"
        }
    
    async def _validate_zhipu(self, api_key: str) -> Dict:
        """Validate Zhipu API key."""
        url = "https://open.bigmodel.cn/api/paas/v4/models"
        headers = {"Authorization": f"Bearer {api_key}"}
        
        async with aiohttp.ClientSession() as session:
            try:
                async with session.get(url, headers=headers, timeout=10) as response:
                    if response.status == 200:
                        return {
                            "is_valid": True,
                            "status": "active",
                            "models": ["glm-4", "glm-3-turbo"]
                        }
                    else:
                        return {
                            "is_valid": False,
                            "status": "invalid",
                            "error": "Invalid API key"
                        }
            except Exception as e:
                return {
                    "is_valid": False,
                    "status": "error",
                    "error": str(e)
                }


# Global validator instance
validator = KeyValidator()


@router.post("/{key_id}/validate", response_model=ValidationResult)
async def validate_api_key(
    key_id: str,
    current_user: Dict = Depends(get_current_user),
    db=Depends(get_db)
):
    """Validate an API key's connectivity and available models."""
    # Get the API key from database
    doc = await db.api_keys.find_one({
        "_id": ObjectId(key_id),
        "user_id": current_user["id"]
    })
    
    if not doc:
        raise HTTPException(status_code=404, detail="API key not found")
    
    api_key_obj = APIKey.from_dict(doc)
    
    # Decrypt the API key
    encryptor = KeyEncryptor()
    try:
        decrypted_key = encryptor.decrypt(api_key_obj.encrypted_key)
    except ValueError:
        raise HTTPException(status_code=500, detail="Failed to decrypt API key")
    
    # Validate the key
    result = await validator.validate(api_key_obj.provider, decrypted_key)
    
    # Update metadata in database
    metadata_update = {
        "metadata.validation_status": result.status,
        "metadata.last_validated": datetime.utcnow(),
        "metadata.supported_models": result.supported_models,
        "metadata.validation_error": result.error,
        "metadata.response_time_ms": result.response_time_ms
    }
    
    await db.api_keys.update_one(
        {"_id": ObjectId(key_id)},
        {"$set": metadata_update}
    )
    
    # Create audit log
    from ..models.api_key_model import AuditLog
    audit_log = AuditLog(
        user_id=current_user["id"],
        action="validate",
        resource_id=key_id,
        details={
            "status": result.status,
            "is_valid": result.is_valid,
            "cached": result.cached
        },
        result="success" if result.is_valid else "failure",
        error_message=result.error
    )
    await db.audit_logs.insert_one(audit_log.to_dict())
    
    return result


@router.post("/validate-batch", response_model=List[ValidationResult])
async def validate_multiple_keys(
    key_ids: List[str],
    current_user: Dict = Depends(get_current_user),
    db=Depends(get_db)
):
    """Validate multiple API keys concurrently."""
    if len(key_ids) > 10:
        raise HTTPException(status_code=400, detail="Maximum 10 keys can be validated at once")
    
    # Create validation tasks
    tasks = []
    for key_id in key_ids:
        tasks.append(validate_api_key(key_id, current_user, db))
    
    # Run concurrently
    results = await asyncio.gather(*tasks, return_exceptions=True)
    
    # Process results
    validation_results = []
    for i, result in enumerate(results):
        if isinstance(result, Exception):
            validation_results.append(ValidationResult(
                is_valid=False,
                status="error",
                response_time_ms=0,
                supported_models=[],
                error=str(result)
            ))
        else:
            validation_results.append(result)
    
    return validation_results